The layer of geometry kernels provides basic geometric entities of constant size1 and primitive operations on them. Each entity is provided as both a stand-alone class, which is parameterized by a kernel class, and as a type in the kernel class. Each operation in the kernel is provided via a functor class2 in the kernel class and also as either a member function or a global function. See [HHK+01] for more details about this design. Ideally, if the kernel provides all the primitives required, you can use any kernel as a traits class directly with your algorithm or data structure; see also Chapter 4. If you need primitives not provided by the kernel (yet), please read Section 3.6 below.
There are two different coordinate representations available in the kernel at present: Cartesian representation and homogeneous representation. Cartesian representation is the one you are familiar with. A point in the plane is given by its x- and its y-coordinates; a point in space by its x-, y- and z-coordinates. Homogeneous representation can be seen as a divison-free representation of Cartesian coordinates. There is an additional coordinate, sometimes called the homogenizing coordinate. So with homogeneous representation in 2-space, we have coordinates (x,y,w), where w is the homogenizing coordinate, and in 3-space, we have homogeneous coordinates (x,y,z,w). Since Cgal uses homogeneous representation for affine geometry (not for projective geometry), we assume w ≠ 0. The Cartesian representation corresponding to (x0, x1, , xd, w) is (x0/w, x1/w, , xd/w). Hence, homogeneous representation is not unique; (αx,αy,αz,αw) is an alternative representation to (x,y,z,w) for any α ≠ 0. Internally, Cgal always maintains a non-negative homogenizing coordinate.
With the homogeneous representation, division operations can be avoided. Homogeneous representation is advantageous over Cartesian representation whenever systems of linear equations with integral coefficients are to be solved. By Cramer's rule, the rational solutions all have the same denominator D. The Cartesian representation would be
(N0/D, N1/D, , Nd-1/D) |
(N0, N1, , Nd-1, D) |
(N0/D0, N1/D1, , Nd-1/Dd-1) |
(N0 ∏Di /D0, N1∏Di /D1, , Nd-1∏Di /Dd-1, ∏Di ) |
CGAL::Cartesian< FieldNumberType > CGAL::Homogeneous< RingNumberType > CGAL::Simple_cartesian< FieldNumberType > CGAL::Simple_homogeneous< RingNumberType >These are all parameterized by a number type, which is used for storing the coordinates and the arithmetic in the corresponding primitives and predicates. Actually, parameterization of Homogeneous<> involves two number types. While in the internal homogeneous representation, an integral number type is sufficient, rational numbers must sometimes be used outside the internal representation, for example, when the squared length of a vector is computed. To represent such rational values, there is a second number type whose default value is CGAL::Quotient< RingNumberType >. The type of this number type can be accessed as Homogeneous<>::FT. The internally used number type can be accessed as Homogeneous<>::RT. For the sake of a uniform interface for both representations, the Cartesian kernels provide such types as well. For Cartesian representation, both FT and RT map to same number type used everywhere in the implementation of the Cartesian kernel.
Whenever one wants to ensure that predicates are evaluated correctly, an exact number type is usually necessary. As exact computations are time consuming, filtering techniques have been developed. The predicate is first evaluated using efficient but inexact floating point arithmetic. At the same time an error bound is computed that is used to judge the quality of the computed solution. If the solution is not guaranteed to be correct, the predicate is re-evaluated using exact arithmetic. The classes
CGAL::Filtered_kernel< CK > CGAL::Filtered_kernel_adaptor< CK >are adaptors that add such a filtering mechanism to the predicates of a given Kernel CK. Note that only predicates are affected by these adaptors, the constructions are still the same as in the original kernel CK.
The difference between Filtered_kernel and Filtered_kernel_adaptor is that the latter affects the predicate functors in the kernel only while the former also affecs the behaviour of predicates that are implemented as global functions.
The classes for the geometric objects in the kernel have a standardized interface.
Whenever you need a predicate that is not present in the current kernel traits, you should first try to re-use the available predicates (you might rewrite the code or implement the new predicate using existing ones). If this is not feasible (especially for efficiency reasons), we have to decide on adding the new predicate to the kernel traits. If the new predicate is not too special, it will be added. Otherwise you cannot use the kernel as a traits class, but have to use additional traits.
See Section 3.2 on how to derive the homogeneous version of a predicate from the Cartesian version.
1 | In dimension d, an entity of size O(d) is considered to be of constant size. |
2 | A class which defines a member operator(). |
3 | the sum of the degrees of each variable in the monomial |
4 | Note that the dimension of an object might depend on its use. A line in the plane has dimension d-1. As a halfspace, it has dimension d. |